Skip to content

Conversation

@xmkg
Copy link
Member

@xmkg xmkg commented May 8, 2025

This merge proposal implements the Host Compute System, Host Compute Networking, and virtdisk API wrappers needed for the Hyper-V API-based platform backend feature. The merge proposal includes the implementation for each wrapper and the required tests (unit, integration, module integration).

Test prefixes are as follows:

"test_ut": Denotes a unit test
"test_it"
: Denotes an integration test
"test_bb_cit"*: Denotes a component integration (a.k.a big bang) test

All wrappers follow the same design :

API function table

All API calls are dispatched through the API function table. The functions are bound to the real API by default. Tests can override the functions partially or completely as desired.

Examples: hyperv_hcn_api_table.h, hyperv_hcs_api_table.h, hyperv_virtdisk_api_table.h

API Wrapper interface

Defines the high-level interface for the API being wrapped. All API functions return "OperationResult" as the return type, an aggregate type of a status code, and a status message (wide string).

Examples: hyperv_hcn_wrapper_interface.h, hyperv_hcs_wrapper_interface.h, hyperv_virtdisk_wrapper_interface.h

API wrapper implementation

Implements the API wrapper interface.

Examples: hyperv_hcn_api_wrapper.h, hyperv_hcs_api_wrapper.h, hyperv_virtdisk_api_wrapper.h

Parameter type definitions

Encapsulates the parameters needed for a wrapper function. If an API function takes more than 2 parameters, a parameter type definition is defined to encapsulate the parameters.

Examples: hyperv_hcn_create_endpoint_params.h, virtdisk_create_virtual_disk_params.h

MULTI-1775
MULTI-1780
MULTI-1799
MULTI-1694

@xmkg xmkg requested review from georgeliao and ricab May 8, 2025 19:05
@xmkg
Copy link
Member Author

xmkg commented May 8, 2025

Added the original reviewers from the private PR back.

@codecov
Copy link

codecov bot commented May 8, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.31%. Comparing base (105744b) to head (c02b482).
⚠️ Report is 536 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4079   +/-   ##
=======================================
  Coverage   89.31%   89.31%           
=======================================
  Files         259      259           
  Lines       15708    15684   -24     
=======================================
- Hits        14029    14008   -21     
+ Misses       1679     1676    -3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

xmkg added 25 commits June 12, 2025 17:50
It's no longer relevant since the wil::unique* wrappers don't accept deleter callable at construction time. Replaced all wil::* usage with std::unique_ptr RAII wrappers.

[hcs]: Added LocalFree to the API table

[hcn]: Added CoTaskMemFree to the API table

[hyperv-common]: Added GUID -> std::[w]string conversion

[hcn-unit-tests]: Added create network unit tests
- added three primary operations: create, resize and get_info
- added initial set of integration tests
it's redundant for multipass's use case and it's not present in older versions of the API
move common test utilitiest to hyperv_test_utils.h
- Fix CMakeLists parens newline
- Switch to angle bracket include for headers
- Use brace-initializers for members
- Add header guard #endif comments
- Add a few class description comments
- compute_system_from_state() now returns std::optional
- Add trailing comma to last enum/list items
The trace option should be reserved for more verbose logging
than those log calls.
Also validate whether the libraries and their main headers are present
in the environment.
- scsi_devices: explicitly capture params
- use maybe_unused and _ for the legitimate use of unused variables
- constify get_compute_system_state
- add an alias for std::make_unsigned_t<HRESULT>
- remove redundant index specifiers from format strings
- mark auto_remove_path dtor noexcept
- check the return value of _mktemp_s
- check the return values of all calls in component integration tests
@xmkg xmkg force-pushed the feature/hyperv-api-backend-hcs-hcn branch from 02c7448 to f473102 Compare June 12, 2025 14:50
@xmkg xmkg removed the request for review from georgeliao June 12, 2025 16:10
@xmkg xmkg force-pushed the feature/hyperv-api-backend-hcs-hcn branch from a89e940 to f473102 Compare June 12, 2025 17:13
@xmkg xmkg requested review from Sploder12 and sharder996 June 27, 2025 11:30
@xmkg
Copy link
Member Author

xmkg commented Jun 27, 2025

@sharder996 @Sploder12 I'm going to request your reviews as a set of the original reviewers have thinned out a bit. There are significant changes on top of this, which are in this PR: #4080

4080 is a superset of this, so if you review it, you would already have reviewed this one.

Copy link
Contributor

@Sploder12 Sploder12 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extremely good PR, code is very well formatted. Just a couple of small issues and questions!

static_cast<bool>(api.CreateEndpoint),
static_cast<bool>(api.OpenEndpoint),
static_cast<bool>(api.DeleteEndpoint),
static_cast<bool>(api.CoTaskMemFree));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing api.CloseEndpoint and api.CloseNetwork, is this intentional?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sharp eyes :) I'll add them.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid rebasing, I'll make the changes in the succeeding PR.

std::function<decltype(HcnOpenEndpoint)> OpenEndpoint = &HcnOpenEndpoint;
// @ref https://learn.microsoft.com/en-us/virtualization/api/hcn/reference/hcndeleteendpoint
std::function<decltype(HcnDeleteEndpoint)> DeleteEndpoint = &HcnDeleteEndpoint;
// @ref https://learn.microsoft.com/en-us/virtualization/api/hcn/reference/hcndeleteendpoint
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// @ref https://learn.microsoft.com/en-us/virtualization/api/hcn/reference/hcndeleteendpoint
// @ref https://learn.microsoft.com/en-us/virtualization/api/hcn/reference/hcncloseendpoint

// Ensure that function to call is set.
if (nullptr == fn)
{
assert(0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interesting use of assert to change debug/release behavior!

// Perform the operation. The last argument of the all HCN operations (except
// HcnClose*) is ErrorRecord, which is a JSON-formatted document emitted by
// the API describing the error happened. Therefore, we can streamline all API
// calls through perform_operation to perform co
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems this comment got cut off early

fmt::print("{}", info);
}

TEST_F(HyperVVirtDisk_IntegrationTests, DISABLED_resize_shrink)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also disabled?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was an issue with the shrink, but I can't recall what. Multipass does not support shrinking disks anyway, so I haven't spent much time digging further.

// ---------------------------------------------------------

/**
* Success scenario 2: HcnCloseNetwork returns an error.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably meant HcnCloseNetwork doesn't return an error?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, the API call itself will succeed even when HcnCloseNetwork fails. It means the operation has completed successfully (i.e., creating a network), but the cleanup step, which is closing the network, has failed. Overall, the operation is successful, but it's worth issuing a warning message in the unlikely event of a handle close failure.


// ---------------------------------------------------------

TEST_F(HyperVHCNAPI_UnitTests, create_endpoint_failure)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no scenario comment on this one

@sharder996
Copy link
Collaborator

I get some build errors when trying to build locally:

C:\Users\Scott\Documents\multipass\src\platform\backends\hyperv_api\hyperv_api_common.cpp(82): error C3493: 'kGUIDLength' cannot be implicitly captured because no default capture mode has been specified
C:\Users\Scott\Documents\multipass\src\platform\backends\hyperv_api\hyperv_api_common.cpp(85): error C3493: 'kGUIDLengthWithBraces' cannot be implicitly captured because no default capture mode has been specified
C:\Users\Scott\Documents\multipass\src\platform\backends\hyperv_api\hyperv_api_common.cpp(99): error C2737: 'result': const object must be initialized
C:\Users\Scott\Documents\multipass\src\platform\backends\hyperv_api\hyperv_api_common.cpp(101): error C3536: 'result': cannot be used before it is initialized

@xmkg
Copy link
Member Author

xmkg commented Jul 3, 2025

I get some build errors when trying to build locally:

C:\Users\Scott\Documents\multipass\src\platform\backends\hyperv_api\hyperv_api_common.cpp(82): error C3493: 'kGUIDLength' cannot be implicitly captured because no default capture mode has been specified
C:\Users\Scott\Documents\multipass\src\platform\backends\hyperv_api\hyperv_api_common.cpp(85): error C3493: 'kGUIDLengthWithBraces' cannot be implicitly captured because no default capture mode has been specified
C:\Users\Scott\Documents\multipass\src\platform\backends\hyperv_api\hyperv_api_common.cpp(99): error C2737: 'result': const object must be initialized
C:\Users\Scott\Documents\multipass\src\platform\backends\hyperv_api\hyperv_api_common.cpp(101): error C3536: 'result': cannot be used before it is initialized

Interesting... Which compiler?

@sharder996
Copy link
Collaborator

I get some build errors when trying to build locally:

C:\Users\Scott\Documents\multipass\src\platform\backends\hyperv_api\hyperv_api_common.cpp(82): error C3493: 'kGUIDLength' cannot be implicitly captured because no default capture mode has been specified
C:\Users\Scott\Documents\multipass\src\platform\backends\hyperv_api\hyperv_api_common.cpp(85): error C3493: 'kGUIDLengthWithBraces' cannot be implicitly captured because no default capture mode has been specified
C:\Users\Scott\Documents\multipass\src\platform\backends\hyperv_api\hyperv_api_common.cpp(99): error C2737: 'result': const object must be initialized
C:\Users\Scott\Documents\multipass\src\platform\backends\hyperv_api\hyperv_api_common.cpp(101): error C3536: 'result': cannot be used before it is initialized

Interesting... Which compiler?

cmake 3.31.8

@xmkg
Copy link
Member Author

xmkg commented Jul 3, 2025

Interesting... Which compiler?

cmake 3.31.8

... and... which compiler, again? 😃

@sharder996
Copy link
Collaborator

Interesting... Which compiler?

cmake 3.31.8

... and... which compiler, again? 😃

Oh, right, sorry!

λ cl
Microsoft (R) C/C++ Optimizing Compiler Version 19.29.30159 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

Signed-off-by: Mustafa Kemal Gilor <mustafa.gilor@canonical.com>
@xmkg
Copy link
Member Author

xmkg commented Jul 9, 2025

I get some build errors when trying to build locally:

C:\Users\Scott\Documents\multipass\src\platform\backends\hyperv_api\hyperv_api_common.cpp(82): error C3493: 'kGUIDLength' cannot be implicitly captured because no default capture mode has been specified
C:\Users\Scott\Documents\multipass\src\platform\backends\hyperv_api\hyperv_api_common.cpp(85): error C3493: 'kGUIDLengthWithBraces' cannot be implicitly captured because no default capture mode has been specified
C:\Users\Scott\Documents\multipass\src\platform\backends\hyperv_api\hyperv_api_common.cpp(99): error C2737: 'result': const object must be initialized
C:\Users\Scott\Documents\multipass\src\platform\backends\hyperv_api\hyperv_api_common.cpp(101): error C3536: 'result': cannot be used before it is initialized

sigh.. MSVC 19 requires a static in addition to constexpr in order to include a variable in the lambda default capture. It should be fixed now -- I've successfully compiled with the same compiler version.

Copy link
Collaborator

@sharder996 sharder996 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a cursory review at this point. Overall, the code looks good and I didn't have any trouble with functional testing.

However, I'm wondering if this PR can be combined with #4080 in order to review the entire diff. It's difficult to review code that may or may not be changed again and I want to avoid merging something into main that may be incomplete or unfinished because of the need to check both PRs for the final diff.

# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

if(WIN32)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary if we are already selecting linked libraries by platform in src/platform/CMakeLists.txt?

#


if(WIN32)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idem

@xmkg
Copy link
Member Author

xmkg commented Jul 10, 2025

However, I'm wondering if this PR can be combined with #4080 in order to review the entire diff.

4080 is already built upon this PR, so at this point, I'm wondering if I should close this one for good and ask you folks to review it instead. Does that sound good?

@sharder996
Copy link
Collaborator

That would easier imo
@Sploder12 Any opinions?

@xmkg
Copy link
Member Author

xmkg commented Jul 11, 2025

Alright, closing this one, and re-targeting #4080 to main.

@xmkg xmkg closed this Jul 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants